(function (fruit, _, global, undefined) {
    var util = fruit.util = _;
    var toString = Object.prototype.toString;
    var class2type = {
        '[object Boolean]':'Boolean',
        '[object Number]':'Number',
        '[object String]':'String',
        '[object Function]':'Function',
        '[object Array]':'Array',
        '[object Date]':'Date',
        '[object RegExp]':'RegExp',
        '[object Object]':'Object'
    };

    function isIgnoreObj(inObj) {
        return util.isDom(inObj) || util.isUndefined(inObj) || util.isWindow(inObj) || util.isInherited(inObj);
    }

    function clone(inObj) {
        var copy = null;
        var i, key, item;
        if (util.isArray(inObj)) {
            copy = [];
            for (i = 0; item = inObj[i]; i++) {
                copy[i] = util.isPrimitive(item) ? item : clone(item);
            }
        } else {
            copy = {};
            for (key in inObj) {
                item = inObj[key];
                copy[key] = util.isPrimitive(item) ? item : clone(item);
            }
        }
        return copy;
    }

    util.extend(util, {
        getItem:function (target, index) {
            if (target) {
                if (target.getItem) {
                    return target.getItem(index);
                }
                else {
                    return target[index];
                }
            }
        },
        //todo
        getByPath:function (path, context, canExecute) {
            var ctx = context || global;
            var paths, i, item, index;
            if (!path) {
                return;
            }
            paths = path.split(".");
            for (i = 0; i < paths.length; i++) {
                item = paths[i];
                if ((index = item.indexOf('[')) && index > 0) {
                    paths.splice(i, 1, item.slice(0, index), item.slice(
                        index + 1, -1));
                    i--;
                } else {
                    if (ctx = ctx[item], !ctx) {
                        return undefined;
                    }
                }
            }
            if (typeof ctx == 'function' && canExecute) {
                ctx = ctx.call(context);
            }
            return ctx;
        },
        equals:function (source, target) {
            if (source && source.equals) {
                return source.equals(target);
            }
            else if (target && target.equals) {
                return target.equals(source);
            }
            else {
                return source === target;
            }
        },
        setByPath:function (path, value, context) {
            var result, ctx;
            result = ctx = context || global;
            var paths, lastIndex, i;
            paths = path.split(".");
            lastIndex = paths.length - 1;
            for (i = 0; i < lastIndex; i++) {
                ctx = ctx[paths[i]] = ctx[paths[i]] || {};
            }
            //lastIndex && (ctx[paths[lastIndex]] = value);
            ctx[paths[lastIndex]] = value;
            return result[paths[0]];
        },
        namespace:function (inPath,inValue, inContext) {
            var result, path;
            result = path = this.getByPath(inPath, inContext);
            if (path === undefined) {
                result = this.setByPath(inPath,inValue, inContext);
            }
            return result;
        },
        startsWith:function (str1, str2) {
            return str1.indexOf(str2) === 0;
        },
        forEach:function (inTarget, inCallback, inContext) {
            if (!inTarget) {
                return;
            }
            if (inTarget.forEach) {
                return inTarget.forEach(inCallback, inContext);
            } else {
                return util.each(inTarget, inCallback, inContext);
            }
        },
        isPrimitive:function (inObj) {
            var type = class2type[toString.call(inObj)];
            return type === 'Boolean'
                || type === 'Number'
                || type === 'String';
        },
        capitalize:function (inStr) {
            return !inStr ? inStr : inStr.charAt(0).toUpperCase() + inStr.substr(1).toLowerCase();
        },
        isDom:function (inObj) {
            return !!inObj && inObj.nodeType;
        },
        isWindow:function (inObj) {
            return inObj === global;
        },
        isInherited:function (inObj) {
            if (inObj.constructor && !inObj.hasOwnProperty("constructor")
                && !inObj.constructor.prototype.hasOwnProperty("isPrototypeOf")) {
                return true;
            }
            return false;
        },
        deepClone:function (inObj) {
            if (!isIgnoreObj(inObj)) {
                return clone(inObj)
            }
        }
    });
}(fruit, _, fruit.global, undefined));